#include "SessionManager.h"
#include "SessionBase.h"
#include "LogEx.h"
#include "StackTrace.h"
using namespace SGLib;
using namespace std;

SINGLETON_CLASS_INIT(CSessionManager);

void CSessionManager::AddSession(u64 id, CSessionBase *session, bool needCheckAlive)
{
    map<u64, CSessionBase*>::iterator it = m_sessions.find( id );
    if( it != m_sessions.end() )
    {
        LOG_WARN( "[%s][%s][%d] session[%llu] aleardy exist", 
            __FILE__, __FUNCTION__, __LINE__, id );
    }
    m_sessions[ id ] = session;
    if( needCheckAlive )
    {
        // add to check queue when session connected.
        _PushCheckQueue( id );
    }
}

void CSessionManager::RemoveSession(u64 id)
{
    map<u64, CSessionBase*>::iterator it = m_sessions.find( id );
    if( it != m_sessions.end() )
    {
        m_sessions.erase( it );
    }
}

void CSessionManager::AddRpcServer(u64 sid, const char *ip, s32 port, SGLib::IPacketParser *parser)
{
    CConnSession *s = new CConnSession( sid, ip, port, parser );
    SELF_ASSERT(s, return;);
    map<u64, CConnSession*>::iterator it = m_rpcServers.find( sid );
    if( it != m_rpcServers.end() )
    {
        LOG_WARN( "[%s][%s][%d] rpc[%llu][%s:%d] aleardy exist", 
            __FILE__, __FUNCTION__, __LINE__, 
            sid, it->second->GetIp(), it->second->GetPort() );
    }
    m_rpcServers[ sid ] = s;
    LOG_INFO( "[%s][%s][%d] add rpc[%llu][%s:%d]", 
        __FILE__, __FUNCTION__, __LINE__, 
        sid, ip, port );
}

void CSessionManager::RpcConnect(u64 sid)
{
    CConnSession *s = FindRpcServer( sid );
    if( !s )
    {
        LOG_ERROR( "[%s][%s][%d] sid[%llu]", 
            __FILE__, __FUNCTION__, __LINE__, sid );
        return;
    }
    s->Connect();

    LOG_WARN( "[%s][%s][%d] sid[%llu]", 
        __FILE__, __FUNCTION__, __LINE__, sid );
}

void CSessionManager::RpcConnected(u64 sid, SGLib::CIoSocketEx *rpc)
{
    CConnSession *s = FindRpcServer( sid );
    if( !s )
    {
        LOG_ERROR( "[%s][%s][%d] sid[%llu]", 
            __FILE__, __FUNCTION__, __LINE__, sid );
        return;
    }
    s->OnConnected( rpc );
}

void CSessionManager::RpcClosed(u64 sid)
{
    CConnSession *s = FindRpcServer( sid );
    if( !s )
    {
        LOG_ERROR( "[%s][%s][%d] sid[%llu]", 
            __FILE__, __FUNCTION__, __LINE__, sid );
        return;
    }
    LOG_WARN( "[%s][%s][%d] sid[%llu]", 
            __FILE__, __FUNCTION__, __LINE__, sid );
    s->OnClose();
}

void CSessionManager::AddServer(u64 id, CSessionBase *server)
{
    map<u64, CSessionBase*>::iterator it = m_servers.find( id );
    if( it != m_servers.end() )
    {
        LOG_WARN( "[%s][%s][%d] server[%llu] aleardy exist", 
            __FILE__, __FUNCTION__, __LINE__, id );
    }
    m_servers[ id ] = server;
}

void CSessionManager::RemoveServer(u64 id)
{
    map<u64, CSessionBase*>::iterator it = m_servers.find( id );
    if( it != m_servers.end() )
    {
        m_servers.erase( it );
    }
}

CSessionBase* CSessionManager::FindSession(u64 id)
{
    map<u64, CSessionBase*>::iterator it = m_sessions.find( id );
    if( it != m_sessions.end() )
    {
        return it->second;
    }
    return NULL;
}

CConnSession* CSessionManager::FindRpcServer(u64 id)
{
    map<u64, CConnSession*>::iterator it = m_rpcServers.find( id );
    if( it != m_rpcServers.end() )
    {
        return (it->second);
    }
    return NULL;
}

CSessionBase* CSessionManager::FindServer(u64 id)
{
    map<u64, CSessionBase*>::iterator it = m_servers.find( id );
    if( it != m_servers.end() )
    {
        return it->second;
    }
    return NULL;
}

s32 CSessionManager::SessionCount()
{
    return (s32)m_sessions.size();
}

void CSessionManager::CheckSessionAlive()
{
    static const s32 CHECK_COUNT = 1000;
    s32 checkCount=0, aliveCount=0, closeCount=0, nullCount=0;
    vector<u64> vecAlive;
    for( s32 i=0; i<CHECK_COUNT; ++i, ++checkCount )
    {
        u64 sid = 0;
        if( !_PopCheckQueue(sid) )
        {
            break;
        }

        CSessionBase *s = FindSession( sid );
        if( s )
        {
            if( s->IsAlive() )
            {
                ++aliveCount;
                vecAlive.push_back( sid );
            }
            else
            {
                ++closeCount;
                LOG_WARN( "[%s][%s][%d] client[%llu] not alive, close", 
                    __FILE__, __FUNCTION__, __LINE__, sid );
                s->Close();
            }
        }
        else
        {
            ++nullCount;
        }
    }

    if( vecAlive.size() > 0 )
    {
        m_checkQueue.insert( m_checkQueue.end(), vecAlive.begin(), vecAlive.end() );
    }

    LOG_WARN( "[%s][%s][%d] checkCount[%d] aliveCount[%d] closeCount[%d] nullCount[%d]", 
        __FILE__, __FUNCTION__, __LINE__,
        checkCount, aliveCount, closeCount, nullCount );
}

void CSessionManager::DumpSessions(std::vector<CSessionBase*> &sessions)
{
    map<u64, CSessionBase*>::iterator it = m_sessions.begin();
    for( ; it != m_sessions.end(); ++it )
    {
        sessions.push_back( it->second );
    }
}

void CSessionManager::DumpServers(std::vector<CSessionBase*> &servers)
{
    map<u64, CSessionBase*>::iterator it = m_servers.begin();
    for( ; it != m_servers.end(); ++it )
    {
        servers.push_back( it->second );
    }
}

void CSessionManager::DumpRpcServers(std::vector<CConnSession*> &rpcServers)
{
    map<u64, CConnSession*>::iterator it = m_rpcServers.begin();
    for( ; it != m_rpcServers.end(); ++it )
    {
        rpcServers.push_back( it->second );
    }
}

void CSessionManager::_PushCheckQueue(u64 sid)
{
    m_checkQueue.push_back( sid );
}

bool CSessionManager::_PopCheckQueue(u64 &sid)
{
    sid = 0;
    if( !m_checkQueue.empty() )
    {
        sid = m_checkQueue.front();
        m_checkQueue.pop_front();
        return true;
    }
    else
    {
        return false;
    }
}

